<?
/**
 * Gravy Database Handling Class.
 *
 * This is Gravy's database handling class, and is used to streamline most of the basic database tasks.
 *
 * @author Lars Sorhus (lars@saucecode.com.au)
 * @internal It's not recommended at all to modify this code.
 * @package database
 */
class database extends errorHandler{

        /**
         * Database Link
         * @var integer
         */
	public $link=false;

        /**
         * Database Connected Flag
         *
         * This variable is set by Gravy to say whether PHP is connected to the database or not.
         *
         * @var boolean
         */
	public $result=null;
	public $affectedRows=0;
	public $rows;
	public $row;
	public $eof=true;

        /**
         * <b>Insert ID</b>
         *
         * This class updates this variable with the last updated or inserted row ID.
         *
         * @var integer
         */
	public $insertId=0;

        public $index=0;
	public $getRowCount=false;
	public $rowCount=0;

	public $cache=0;

        /**
         * Database Connected Flag
         *
         * This variable is set by Gravy to say whether PHP is connected to the database or not.
         *
         * @var boolean
         */
        private $connected=false;
        
	public $gravy=NULL;

	public function __construct(&$gravy){
		parent::__construct();
		$this->gravy=$gravy;
	}

	public function connect($db,$un,$pw,$host="localhost"){
		$result=false;
		if($this->connected){
			$result=true;
		}else{
			if(isset($db)&&isset($host)&&isset($un)&&isset($pw)){
				$this->link=mysql_connect($host,$un,$pw);
				if($this->link){
					$isDbSelectError=false;
					mysql_select_db($db,$this->link) or $isDbSelectError=true;
					if($isDbSelectError||!$this->link||$this->link===NULL){
						$this->addError($this->ERROR_DB_SELECT,"database.connect.databaseCantSelect",array("mysql_error"=>mysql_error($this->link),"db"=>$db,"un"=>$un,"pw"=>$pw,"host"=>$host));
					}else{
						$result=true;
						$this->connected=true;
					}
				}else{
					$this->addError($this->ERROR_DB_LINK,"database.connect.databaseCantConnect",array("mysql_error"=>mysql_error($this->link),"db"=>$db,"un"=>$un,"pw"=>$pw,"host"=>$host));
				}
			}else{
				$this->debug("Error with database login credentials",array("db"=>$db,"un"=>$un,"pw"=>$pw,"host"=>$host));
			}
		}
		return($result);
	}

	public function getQueryType($sQl="SELECT"){
		$sQl=str_replace(array("\n","\r")," ",$sQl);
		list($result)=explode(' ',trim($sQl));
		$result=trim(strtolower($result));
		$result=array($result=="insert",$result=="select",$result=="update",$result=="delete",$result=="show",$result=="describe");
		return($result);
	}
	
	public function exec($sQl,$saveResultArray=false,$errorOnNoAffectedRows=false){
		$result=false;
		$runQuery=true;
		$row_count=0;
		if(DEBUG){
			$this->debug("database->exec",$sQl);
		}
		if($this->connected){
			list($isInsert,$isSelect,$isUpdate,$isDelete,$isShow,$isDescribe)=$this->getQueryType($sQl);
			if($isSelect||$isShow||$isDescribe){
				if($this->cache>0){
					$this->debug("Checking if cache file is older than {$this->cache} seconds.");
					$cache=new cacher();
					if($result=$cache->load($sQl,$this->cache)){
						#$this->debug("Got a cache file");
						$this->rows=$result->rows;
						$this->row=$result->row;
						$this->result=$result->result;
						$this->affectedRows=$result->affectedRows;
						$this->eof=$result->eof;
						$this->insertId=$result->insertId;
						$this->index=$result->index;
						$this->getRowCount=$result->getRowCount;
						$this->rowCount=$result->rowCount;
						$result=($this->affectedRows>0);
						$runQuery=false;
					}
				}
			}
			if($runQuery){
				#$this->debug("sQl",$sQl);
				$this->result=mysql_query($sQl,$this->link);
				if($this->result){
					$this->affectedRows=mysql_affected_rows($this->link);
					if($this->affectedRows>0||!$errorOnNoAffectedRows){
					    
						#If its a select, get the first row, no matter what.
						#If saveResultArray get all the rows (dont really use that ever, use recordsetting instead)
						if($isSelect||$isShow||$isDescribe){
							$this->rows=array();
							$this->row=mysql_fetch_assoc($this->result);
							array_push($this->rows,$this->row);
							$this->index=0;
							if($saveResultArray){
								while($ar=mysql_fetch_assoc($this->result)){
									array_push($this->rows,$ar);
								}
							}
							$this->eof=($this->affectedRows>0)?false:true;
							$result=($this->affectedRows>0);
	
							#Check if they want a real row count (i.e. no limiting).
							if($this->getRowCount){
								#$this->debug("yep getting row count");
								if(strpos(strtolower($sQl),"limit")>0){
									$ar=split("FROM",$sQl,2);
									#$sQl2=eregi_replace("SELECT.*FROM","SELECT COUNT(*) rc FROM",$sQl);
									if(count($ar)==2){
										$sQl2="SELECT COUNT(*) rc FROM ".$ar[1];
									}
									$sQl2=eregi_replace("ORDER BY.{1,}","",$sQl2);
									$sQl2=eregi_replace("GROUP BY.{1,}","",$sQl2);
									#$this->debug("replaced sql",$sQl2);
									#$this->debug("ar sql",$ar);
									$res=mysql_query($sQl2,$this->link);
									if($res){
										$data=mysql_fetch_assoc($res);
										$this->rowCount=(int)$data["rc"];
									}
								}
							}
							if($this->cache>0){
								$cache->cache($sQl,$this,$this->cache);
							}
						}elseif($isInsert){
							$this->insertId=mysql_insert_id($this->link);
							$this->log("database->exec(\"$sQl\"); Affected Rows: ".$this->affectedRows);
							$result=true;
						}elseif($isUpdate||$isDelete){
							$this->log("database->exec(\"$sQl\"); Affected Rows: ".$this->affectedRows);
							$result=true;
						}
					}else{
						$this->addError($this->ERROR_DB_NO_ROWS_AFFECTED,"database.exec.noRowsAffected",array("mysql_error"=>mysql_error($this->link),"sQl"=>$sQl));
					}
				}else{
					#$this->debug("Database Error",$sQl);
					$this->addError($this->ERROR_DB_QUERY,"database.exec.queryError",array("mysql_error"=>mysql_error($this->link),"sQl"=>$sQl));
				}
			}
		}else{
			$this->addError($this->ERROR_DB_CONNECTION,"database.exec.databaseNotConnected",array("mysql_error"=>mysql_error(),"sQl"=>$sQl));
		}
		return($result);
	}
	
	public function moveNext(){
		$result=false;
		if($ar=mysql_fetch_assoc($this->result)){
			$this->row=$ar;
			array_push($this->rows,$ar);
			$this->index++;
			$result=true;
			if($this->index>=$this->affectedRows){
				$this->eof=true;
			}
		}else{
			$this->eof=true;
		}
		return($result);
	}

	public function escape($value=NULL,$quote=true){
		$result="NULL";
		if(strtolower($value)=="null"){
			$result="'".$value."'";
		}else{
			if($value===0||$value===FALSE){
				$result='0';
				$quote=false;
			}elseif($this->connected){
				if($value!=NULL){
					$result=mysql_real_escape_string($value);
					#$this->debug("db->val is not null",$value);
				}
			}else{
				$result=$value;
				$result=str_replace("\\'","'",$result);
				$result=str_replace("'","\\'",$result);
				$result=str_replace("%","\\%",$result);
				$result=str_replace("(","\\(",$result);
				$result=str_replace(")","\\)",$result);
				#$this->addError($this->ERROR_DB_CONNECTION,"database.escape.databaseNotConnected",array("mysql_error"=>mysql_error(),"value"=>$value));
				#$this->debug("Database not connected, cant escape.");
			}
			if($quote&&$result!="NULL"){
				$result="'$result'";
			}
		}
		return($result);
	}
	/*
	public function escape($value=NULL,$quote=true){
		$result=NULL;
		if($this->connected){
			if($value!==NULL || $value===0 || is_numeric($value)){
				if(strtolower($value)=="null"){
					$result="'$value'";
				}else{
					$result=mysql_real_escape_string($value);
					#$this->debug("db->val is not null",$value);
					if($quote){
						$result="'$result'";
					}
				}
			}
		}elseif($value!==NULL){
			$result=$value;
			$result=str_replace("\\'","'",$result);
			$result=str_replace("'","\\'",$result);
			$result=str_replace("%","\\%",$result);
			$result=str_replace("(","\\(",$result);
			$result=str_replace(")","\\)",$result);
			#$this->addError($this->ERROR_DB_CONNECTION,"database.escape.databaseNotConnected",array("mysql_error"=>mysql_error(),"value"=>$value));
			#$this->debug("Database not connected, cant escape.");
			if($quote){
				$result="'$result'";
			}
		}else{
			$result="NULL";
		}
		return($result);
	}
	*/
	public function close(){
		if($this->connected&&is_resource($this->link)){
			$this->connected=false;
			mysql_close($this->link);
		}
		return(true);
	}
}
?>